package com.jplus.service.impl;

import com.jplus.VO.ResultVO;
import com.jplus.dao.OrderDao;
import com.jplus.dao.UserDao;
import com.jplus.dao.UserInfoDao;
import com.jplus.dao.VarDao;
import com.jplus.dto.BasicOrderDTO;
import com.jplus.dto.MyOrdersOrderDTO;
import com.jplus.entity.Location;
import com.jplus.entity.Order;
import com.jplus.entity.User;
import com.jplus.enums.ResultEnum;
import com.jplus.exception.SFUmbrellaException;
import com.jplus.listener.MySessionContext;
import com.jplus.service.OrderService;
import com.jplus.utils.OrderCodeUtils;
import com.jplus.utils.ResultVOUtils;
import com.jplus.websocket.MyClient;
import com.jplus.websocket.MyClientApp;
import com.jplus.websocket.MyWebSocket;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
@Slf4j
@Transactional
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderDao orderDao;

    @Autowired
    private VarDao varDao;

    @Autowired
    private UserDao userDao;

    @Autowired
    private UserInfoDao userInfoDao;

    @Override
    public ResultVO createOrder(Location location, String sessionId) {
        /**
         * 创建订单过程：
         * 0.先判断用户是否有未完成的订单，有则不允许下单。
         * 1. 用户下单，传入用户的信息、以及位置信息
         * 2. 生成订单，写入到数据库
         * 3. 然后将订单消息（位置信息）推送出去，等待他人接单
         * 4. 他人接单后，根据businessId，写入接单人的id
         * 5. 订单状态设为1，表示订单可用
         */
        try {
            // 1.获取顾客信息
            MySessionContext myc = MySessionContext.getInstance();
            // 通过sessionId拿到用户登录状态
            HttpSession session = myc.getSession(sessionId);
            User customer = (User) session.getAttribute("customer");
            if (customer == null) {
                log.error("用户不存在，请先登录");
                return ResultVOUtils.error(0, "用户为空，请先登录");
            }
            // 判断用户是否有未完成的订单
            if (orderDao.getUnCompletedOrders(customer.getId()).size() != 0) {
                log.error("存在尚未完成的订单");
                return ResultVOUtils.error(3, "存在尚未完成的订单，请先结束未完成的订单");
            }
            // 2.创建订单实体，只需11种数据
            Order order = new Order();
            String businessId = OrderCodeUtils.makeOrderCode();
            order.setBusinessId(businessId);
            order.setLocationStart(location.getLocationStart());
            order.setLocationEnd(location.getLocationEnd());
            order.setDistance(location.getDistance());
            order.setOrderAmount(varDao.getOrderUnitPrice() * order.getDistance());
            // 设置起始位置的经纬度
            order.setLatitudeStart(location.getLatitudeStart());
            order.setLongitudeStart(location.getLongitudeStart());
            order.setLatitudeEnd(location.getLatitudeEnd());
            order.setLongitudeEnd(location.getLongitudeEnd());
            order.setUmbrellaType(location.getUmbrellaType());
            order.setCustomUid(customer.getId());
            // 修改订单状态为 1：等待接单
            order.setOrderStatus(1);
            // 3.写入订单信息
            orderDao.insertOneOrder(order);
            log.info("businessID为:{}的订单创建成功{}", businessId, new Date());
            // 整理订单DTO， 只要9种数据
            BasicOrderDTO basicOrderDTO = new BasicOrderDTO();
            basicOrderDTO.setCustomerNickName(userInfoDao.getNickNameByUserId(customer.getId()));
            basicOrderDTO.setCustomerPhone(customer.getPhone());
            basicOrderDTO.setCustomerSex(userInfoDao.getUserSexInfoByUserId(customer.getId()));
            basicOrderDTO.setDistance(order.getDistance());
            basicOrderDTO.setLocationEnd(order.getLocationEnd());
            basicOrderDTO.setLocationStart(order.getLocationStart());
            basicOrderDTO.setOrderAmount(order.getOrderAmount());
            basicOrderDTO.setPayStatus(order.getPayStatus());
            basicOrderDTO.setBusinessId(order.getBusinessId());
            basicOrderDTO.setOrderStatus(order.getOrderStatus());
            // 订单推送，主要是为了将新订单实时加入到抢单页
            MyClient client = new MyClient();
            MyClientApp.pushNewOrderToAllUser(client);
            client.closeSocket();
            log.info("订单{}推送成功，时间{}", order.getBusinessId(), new Date());
            return ResultVOUtils.success(basicOrderDTO);
        } catch (Exception e) {
            log.error("订单创建失败{}", new Date());
            throw new SFUmbrellaException(ResultEnum.ORDER_CREATE_ERROR);
        }
    }

    /**
     * 系统里面存在三种用户：
     * 1.customer：纯粹要顺风伞的顾客
     * 2.admin：系统管理员
     * 3.businessUser：要接单的有伞的人 --> 其实就是另外一种customer
     *
     * @param sessionId
     * @param
     * @return
     */
    @Override
    public ResultVO acceptOrder(String sessionId, String businessId) {
        // 1.获取顾客信息
        MySessionContext myc = MySessionContext.getInstance();
        // 通过sessionId拿到用户登录状态
        HttpSession session = myc.getSession(sessionId);
        User businessUser = null;
        Order order = null;
        try {
            // 1.获取接单人信息,如果接单的人不登录，则要提示！
            businessUser = (User) session.getAttribute("customer");
            if (businessUser == null) {
                return ResultVOUtils.error(0, "请先登录再抢单");
            }
            // 2.获取要确认的订单
            order = orderDao.getOneOrderByBusinessId(businessId);
            // 2.1判断是否为自己接自己的订单
            if (order.getCustomUid().equals(businessUser.getId())) {
                return ResultVOUtils.error(2, "禁止自己抢自己的订单");
            }
            // 判断用户是否有未完成的订单
            if (orderDao.getUnCompletedOrders(businessUser.getId()).size() != 0) {
                log.error("存在尚未完成的订单");
                return ResultVOUtils.error(3, "存在尚未完成的订单，请先结束未完成的订单");
            }
            // 3.更新订单信息
            order.setBusinessUid(businessUser.getId());
            // 3.1接单成功修改订单状态为 2：等待行程结束/等待支付
            order.setOrderStatus(2);
            order.setAccepted(1);
            // 4.写入修改该订单businessId的accepted为1
            orderDao.updateAcceptedOrderByBusinessId(order);
            // 5.推送通知
            String phone = userDao.getUserById(order.getCustomUid()).getPhone();
            MyClientApp.pushMyOrderModifyToUserId(phone);
        } catch (Exception e) {
            log.error("接单异常{}, 时间{}", e.getCause(), new Date());
            throw new SFUmbrellaException(ResultEnum.ORDER_ACCEPT_FAILED);
        }
        return ResultVOUtils.success(order);
    }

    @Override
    public ResultVO cancelOrder(String sessionId, String businessId) {
        /**
         * 顾客取消订单：
         *      1.accepted：0
         *      2.cancel： 1
         *      3.orderStatus：3
         *
         * 抢单人取消订单：
         *      1.accepted：0
         *      2.cancel：0
         *      3.orderStatus：1
         *      4.businessUid：null
         * */
        // 1.获取顾客信息
        MySessionContext myc = MySessionContext.getInstance();
        // 通过sessionId拿到用户登录状态
        HttpSession session = myc.getSession(sessionId);
        User user = null;
        Order order = null;
        try {
            user = (User) session.getAttribute("customer");
            order = orderDao.getOneOrderByBusinessId(businessId);
            if (user.getId().equals(order.getCustomUid())) {
                // 当前用户为顾客
                orderDao.customerUserCancelOrder(businessId);

                MyClient client = new MyClient();
                MyClientApp.pushNewOrderToAllUser(client);
                client.closeSocket();
            } else if (user.getId().equals(order.getBusinessUid())) {
                // 当前用户为接单人
                orderDao.businessUserCancelOrder(businessId);
                MyClientApp.pushMyOrderModifyToUserId(userDao.getUserById(order.getCustomUid()).getPhone());
            } else {
                return ResultVOUtils.error(0, "订单取消失败,请检查用户id与订单id是否合法");
            }

        } catch (Exception e) {
            log.error("取消订单失败");
            throw new SFUmbrellaException(ResultEnum.ORDER_CANCEL_FAILED);
        }
        return ResultVOUtils.success("订单取消成功");
    }

    @Override
    public ResultVO showUnacceptedOrders(HttpServletRequest request) {
        /*
         抢单页也得自己更新
         系统每次加载订单页的时候，就扫描数据库里面accepted的字段
        */
        List<Order> orders = null;
        List<BasicOrderDTO> basicOrderDTOS = new ArrayList<>();
        try {
            // 获取全部的未被接单的订单
            orders = orderDao.getAllUnacceptedOrders();
            for (Order order : orders) {
                // new出DTO、找到订单发起者的user
                BasicOrderDTO basicOrder = new BasicOrderDTO();
                User customer = userDao.getUserById(order.getCustomUid());
                // 开始写入DTO数据
                basicOrder.setBusinessId(order.getBusinessId());
                basicOrder.setLocationEnd(order.getLocationEnd());
                basicOrder.setLocationStart(order.getLocationStart());
                basicOrder.setDistance(order.getDistance());
                basicOrder.setOrderAmount(order.getOrderAmount());
                basicOrder.setOrderStatus(order.getOrderStatus());
                SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
                basicOrder.setCreateTime(sf.format(order.getCreateTime()));
                basicOrder.setCustomerNickName(userInfoDao.getNickNameByUserId(customer.getId()));
                basicOrder.setCustomerPhone(customer.getPhone());
                // TODO 优化数据库sql语句，使用多表级联查询
                basicOrder.setCustomerSex(userInfoDao.getUserSexInfoByUserId(customer.getId()));
                basicOrder.setUmbrellaType(order.getUmbrellaType());
                basicOrderDTOS.add(basicOrder);
            }
        } catch (Exception e) {
            log.error("未被接单的订单加载出错{}", e.getMessage());
            throw new SFUmbrellaException(0, "未被接单的订单加载出错");
        }
        return ResultVOUtils.success(basicOrderDTOS);
    }

    @Override
    public ResultVO getAllMyPublishedOrders(String sessionId) {
        MySessionContext myc = MySessionContext.getInstance();
        HttpSession session = myc.getSession(sessionId);
        // 查询出数据库订单表里面所有customerUid等于用户id的元组
        List<Order> orders = null;
        List<MyOrdersOrderDTO> myPublishedDTOS = new ArrayList<>();
        User customer = null;
        try {
            customer = (User) session.getAttribute("customer");
        } catch (Exception e) {
            e.printStackTrace();
            log.error("从session里面获取customer失败，原因：{}", e.getCause());
            throw new SFUmbrellaException(0, "customer获取失败");
        }
        try {
            // 该集合内容全部为我发布的，需要填入接单人信息
            orders = orderDao.getAllMyPublishedOrdersById(customer.getId());
        } catch (Exception e) {
            e.printStackTrace();
            log.error("getAllMyPublishedOrdersById失败，原因：{}", e.getCause());
            throw new SFUmbrellaException(0, "customer订单获取失败");
        }
        for (Order order : orders) {
            // 寻找每个订单元组的接单人信息
            User business = null;
            try {
                business = userDao.getUserById(order.getBusinessUid());
            } catch (Exception e) {
                e.printStackTrace();
                log.error("getUserById获取business异常，原因{}", e.getCause());
                throw new SFUmbrellaException(0, "从数据库获取business User异常");
            }
            MyOrdersOrderDTO myPublished = new MyOrdersOrderDTO();
            myPublished.setCurrentUserId(customer.getId());
            myPublished.setCustomerUid(order.getCustomUid());
            myPublished.setBusinessUid(order.getBusinessUid());
            myPublished.setBusinessId(order.getBusinessId());
            myPublished.setLocationEnd(order.getLocationEnd());
            myPublished.setLocationStart(order.getLocationStart());
            myPublished.setDistance(order.getDistance());
            myPublished.setOrderAmount(order.getOrderAmount());
            myPublished.setOrderStatus(order.getOrderStatus());
            myPublished.setPayStatus(order.getPayStatus());
            SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            myPublished.setCreateTime(sf.format(order.getCreateTime()));
            myPublished.setAccepted(order.getAccepted());
            myPublished.setCancel(order.getCancel());
            myPublished.setCustomerNickName(userInfoDao.getNickNameByUserId(customer.getId()));
            myPublished.setCustomerPhone(customer.getPhone());
            if (business != null) {
                myPublished.setBusinessNickName(userInfoDao.getNickNameByUserId(business.getId()));
                myPublished.setBusinessPhone(business.getPhone());
            }
            try {
                myPublished.setCustomerSex(userInfoDao.getUserSexInfoByUserId(customer.getId()));
                myPublished.setBusinessSex(userInfoDao.getUserSexInfoByUserId(order.getBusinessUid()));
            } catch (Exception e) {
                log.warn("订单性别加载异常");
                System.out.println("订单性别加载异常");
            }
            try {
                myPublished.setUmbrellaType(order.getUmbrellaType());
            } catch (Exception e) {
                e.printStackTrace();
                log.warn("订单雨伞类型加载异常");

            }
            myPublishedDTOS.add(myPublished);
        }

        return ResultVOUtils.success(myPublishedDTOS);
    }

    @Override
    public ResultVO getAllMyGotOrders(String sessionId) {
        MySessionContext myc = MySessionContext.getInstance();
        HttpSession session = myc.getSession(sessionId);
        // 查询出数据库订单表里面所有businessUid等于用户id的元组
        List<Order> orders = null;
        List<MyOrdersOrderDTO> myGotDTOS = new ArrayList<>();
        // 当前用户是在session里面customer，但是在业务上是business
        User business = null;
        try {
            business = (User) session.getAttribute("customer");
        } catch (Exception e) {
            e.printStackTrace();
            log.error("从session里面获取business的customer失败，原因：{}", e.getCause());
            throw new SFUmbrellaException(0, "business的customer获取失败");
        }
        try {
            // 该集合内容全部为我抢的，需要填入顾客信息
            orders = orderDao.getAllMyGotOrdersById(business.getId());
        } catch (Exception e) {
            e.printStackTrace();
            log.error("getAllMyGotOrdersById失败，原因：{}", e.getCause());
            throw new SFUmbrellaException(0, "business订单获取失败");
        }
        if (orders.size() != 0) {
            for (Order order : orders) {
                // 寻找每个订单元组的顾客信息
                User customer = null;
                try {
                    customer = userDao.getUserById(order.getCustomUid());
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error("getUserById获取customer异常，原因{}", e.getCause());
                    throw new SFUmbrellaException(0, "从数据库获取customer User异常");
                }
                MyOrdersOrderDTO myGot = new MyOrdersOrderDTO();
                myGot.setCurrentUserId(business.getId());
                myGot.setCustomerUid(order.getCustomUid());
                myGot.setBusinessUid(order.getBusinessUid());
                myGot.setBusinessId(order.getBusinessId());
                myGot.setLocationEnd(order.getLocationEnd());
                myGot.setLocationStart(order.getLocationStart());
                myGot.setDistance(order.getDistance());
                myGot.setOrderAmount(order.getOrderAmount());
                myGot.setOrderStatus(order.getOrderStatus());
                myGot.setPayStatus(order.getPayStatus());
                SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
                myGot.setCreateTime(sf.format(order.getCreateTime()));
                myGot.setAccepted(order.getAccepted());
                myGot.setCancel(order.getCancel());
                myGot.setCustomerNickName(userInfoDao.getNickNameByUserId(customer.getId()));
                myGot.setCustomerPhone(customer.getPhone());
                myGot.setBusinessNickName(userInfoDao.getNickNameByUserId(business.getId()));
                myGot.setBusinessPhone(business.getPhone());
                try {
                    myGot.setCustomerSex(userInfoDao.getUserSexInfoByUserId(customer.getId()));
                    myGot.setBusinessSex(userInfoDao.getUserSexInfoByUserId(order.getBusinessUid()));
                } catch (Exception e) {
                    log.warn("订单性别加载异常");
                    System.out.println("订单性别加载异常");
                }
                try {
                    myGot.setUmbrellaType(order.getUmbrellaType());
                } catch (Exception e) {
                    e.printStackTrace();
                    log.warn("订单雨伞类型加载异常");
                }
                myGotDTOS.add(myGot);
            }
            return ResultVOUtils.success(myGotDTOS);
        } else {
            return ResultVOUtils.success(orders);
        }
    }

    @Override
    public ResultVO pay(String payChannel, String escrowTradeNo, String businessId) {
        try {
            orderDao.pay(payChannel, escrowTradeNo, new Date(), businessId);
            Order order = orderDao.getOneOrderByBusinessId(businessId);
            User u = userDao.getUserById(order.getBusinessUid());
            MyClientApp.pushMyOrderModifyToUserId(u.getPhone());
        } catch (Exception e) {
            e.printStackTrace();
            log.warn("订单{}支付失败", businessId);
            throw new SFUmbrellaException(0, "订单" + businessId + "支付失败");
        }
        return ResultVOUtils.success("订单" + businessId + "支付成功");
    }

    @Override
    public ResultVO getUmbrellaTypeArray() {
        List<String> umbrellaTypeArray = null;
        try {
            umbrellaTypeArray = orderDao.getUmbrellaTypeArray();
        } catch (Exception e) {
            e.printStackTrace();
            log.warn("获取用户持有雨伞类型失败");
            throw new SFUmbrellaException(0, "获取用户持有雨伞类型失败");
        }
        return ResultVOUtils.success(umbrellaTypeArray);
    }

}
